﻿using System;
using System.IO;
using System.Reflection;
using NRex.Logging;

namespace NRex
{
    internal class DependencyTreeLister
    {
        private readonly ILogger _logger;

        public DependencyTreeLister(ILogger logger)
        {
            _logger = logger;
        }

        public void ProcessFile(string file)
        {
            if (!File.Exists(file))
            {
                _logger.Error("Cannot find {0}", file);
                return;
            }

            Assembly assembly = null;
            if (!TryLoadAssemblyFrom(file, ref assembly))
            {
                _logger.Error("Failed to load {0}", file);
                return;
            }

            PrintReferencesTree(assembly);
        }

        private void PrintReferencesTree(Assembly assembly, int indentLevel = 0)
        {
            string indenter = GetIndenter(indentLevel);

            _logger.Info("{0}{1} references", indenter, assembly.GetName().Name);
            foreach (var referenced in assembly.GetReferencedAssemblies())
            {
                _logger.Info("{0}version {1} of {2} ", indenter, referenced.Version, referenced.Name);
                if (referenced.Name == "mscorlib" || referenced.Name.StartsWith("System"))
                    continue;

                try
                {
                    var asm = Assembly.Load(referenced);
                    PrintReferencesTree(asm, indentLevel+1);
                }
                catch (Exception)
                {
                    continue;
                }
            }
        }

        private static string GetIndenter(int indentLevel)
        {
            string indenter = "";
            return indenter.PadLeft(indentLevel, '\t');
        }

        private static bool TryLoadAssemblyFrom(string file, ref Assembly assembly)
        {
            try
            {
                assembly = Assembly.LoadFrom(file);
                return true;
            }
            catch
            {
                return false;
            }
        }
    }
}